////////////////////////////////////////////////////////////////////////////////
// This file is part of the Mist compiler.                                    //
//                                                                            //
// Copyright (C) 2009 The Mist project                                        //
//                                                                            //
// For a list of contributors, see the COMMITTERS file.                       //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// in the COPYING file. If not, see <http://www.gnu.org/licenses/>.           //
////////////////////////////////////////////////////////////////////////////////

///
/// \file
/// Contains the Symbol class.
///

#ifndef SYMBOL_HPP
#define SYMBOL_HPP

////////////////////////////////////////////////////////////////////////////////
// Includes                                                                   //
////////////////////////////////////////////////////////////////////////////////

#include <string>
using std::string;

#include <set>
using std::set;

#include <map>
using std::map;
using std::multimap;

#include <boost/optional.hpp>
using boost::optional;

#include "common/ptr.hpp"
#include "common/types.hpp"
#include "accesstype.hpp"
#include "tree.hpp"
#include "typespec.hpp"

////////////////////////////////////////////////////////////////////////////////
// Symbol Class                                                               //
////////////////////////////////////////////////////////////////////////////////

class Symbol : public enable_ptr_this<Symbol> {
	public:
		
		//// Static Constructor Methods ////////////////////////////////////////
		
		/// \return the root symbol of a new symbol-tree
		///
		static sptr<Symbol> construct_root();
		
		/// \return a new function symbol (without any children symbols)
		///
		static sptr<Symbol> construct_function(
			wptr<Symbol>              parent,            ///< the parent symbol of the function
			string                    name,              ///< the name of the function
			sptr<FunctionType>        type,              ///< the type of the function
			vector<wptr<Identifier> > templateTypeNames, ///< the names of the function template types
			wptr<FunctionDeclaration> decl               ///< the function declaration
		);
		
		/// \return a new variable symbol
		///
		static sptr<Symbol> construct_variable(
			wptr<Symbol> parent, ///< the parent symbol of the variable
			string       name,   ///< the name of the variable
			sptr<Type>   type    ///< the type of the variable
		);
		
		/// \return a new iterator symbol (constant variable for for-loops)
		///
		static sptr<Symbol> construct_iterator(
			wptr<Symbol> parent, ///< the parent symbol of the iterator
			string       name,   ///< the name of the iterator
			sptr<Type>   type    ///< the type of the iterator
		);
		
		/// \return a new logical variable symbol
		///
		static sptr<Symbol> construct_logical_variable(
			wptr<Symbol> parent, ///< the parent symbol of the logical variable
			string       name,   ///< the name of the logical variable
			sptr<Type>   type    ///< the type of the logical variable
		);
		
		/// \return a new blinder symbol, opaque to limit symbol visibility
		///
		static sptr<Symbol> construct_blinder(
			wptr<Symbol> parent ///< the parent of the blinder symbol
		);
		
		/// \return a new type symbol
		///
		static sptr<Symbol> construct_type(
			wptr<Symbol>          parent,                        ///< the parent of the type symbol
			string                name,                          ///< the name of the type
			wptr<TypeDeclaration> decl = wptr<TypeDeclaration>() ///< a pointer to the type-declaration
		);
		
		/// \return a new scope symbol
		///
		static sptr<Symbol> construct_scope(
			wptr<Symbol> parent,                       ///< the parent symbol of the scope
			optional<string> name = optional<string>() ///< the optional name of the scope
		);
		
		//// Scoping Information ///////////////////////////////////////////////
		
		/// Does this node introduce a new scope? If so, an absolute path to a
		/// symbol inside this scope should include the name of this symbol. If
		/// this symbol does not have a name, there can be no absolute path to
		/// symbols inside.
		///
		bool newScope;
		
		/// Can child-symbols of this symbol be referenced from the outside?
		///
		bool transparent;
		
		//// Individual Symbol Information /////////////////////////////////////
		
		/// The optional name of this symbol. Functions, variables and types
		/// have a name. Scopes may have a name.
		///
		optional<string> name;
		
		/// The optional type-specification (template types and parameter types)
		/// of this node, if it is a function (overload/template).
		///
		optional<TypeSpec> typeSpec;
		
		/// If the symbol is to a template instantiation of a function.
		///
		bool isTemplateInstantiation;
		
		/// If this symbol has template parameters, here the mapping between
		/// template instantiation and symbol will be made.
		///
		map<vector<wptr<Type> >, sptr<FunctionDeclaration>, TypeListOrder> templateInstantiations;
		
		/// The optional type of this scope. Types, variables and functions
		/// have a type.
		///
		sptr<Type> type;
		
		/// The access-type of this symbol. Variables have 'rw', functions and
		/// types have 'r', logical variables have 'l' and symbols that can not
		/// have a value have 'n'. As of yet, nothing can have 'w' (write-only).
		///
		AccessType access;
		
		/// An optional pointer back to the function-declaration of this symbol.
		///
		wptr<FunctionDeclaration> declaration;
		
		/// An optional pointer back to the type-declaration of this symbol.
		///
		wptr<TypeDeclaration> typeDeclaration;
		
		/// An optional pointer back to the compound-statement introducing this scope.
		///
		wptr<CompoundStatement> compoundStatement;
		
		//// Symbol Relations //////////////////////////////////////////////////
		
		/// the root of this symbol-tree
		///
		wptr<Symbol> root;
		
		/// the optional parent of this symbol
		///
		wptr<Symbol> parent;
		
		/// the children of this symbol
		///
		set<sptr<Symbol> > children;
		
		/// the children of this symbol, mapped by name and type-spec
		///
		map<string, multimap<TypeSpec, wptr<Symbol>, TypeSpec::Before> > childrenByName;
		
		/// Insert a nameless child \a symbol.
		///
		void insert_child(sptr<Symbol> symbol);
		
		/// Insert a child \a symbol with name \a name and type-specification \a typeSpec.
		///
		void insert_child(const string& name, const TypeSpec& typeSpec, sptr<Symbol> symbol);
		
		/// \return a name with numbers, letters and underscores, guaranteed to uniquely
		///         identify one symbol in the symbol tree
		///
		string unique_name();
		
		/// \return a new absolute reference to this symbol
		///
		/// If necessary, this function will name unnamed scopes in the AST.
		///
		sptr<Reference> create_absolute_reference(wptr<Symbol> scope);
	
	private:
		
		//// Counting Children /////////////////////////////////////////////////
		
		uint _childCount;
		
		uint _myCountInParent;
};

////////////////////////////////////////////////////////////////////////////////
// Symbol Functions                                                           //
////////////////////////////////////////////////////////////////////////////////

void find_symbol_names(wptr<Symbol> from, set<string>& names);

string new_unique_identifier(wptr<Symbol> from, string prefix);

#endif // SYMBOL_HPP
